package com.lineage.server.command;

import com.lineage.config.Config;
import com.lineage.server.command.executor.L1CommandExecutor;
import com.lineage.server.datatables.CommandsTable;
import com.lineage.server.datatables.RecordTable;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.serverpackets.S_HelpMessage;
import com.lineage.server.serverpackets.S_ServerMessage;
import com.lineage.server.serverpackets.ServerBasePacket;
import com.lineage.server.templates.L1Command;
import com.lineage.server.world.World;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class GMCommands {
  private static final Log _log = LogFactory.getLog(GMCommands.class);
  
  private static GMCommands _instance;
  
  private static Map<Integer, String> _lastCommands = new HashMap<>();
  
  public static GMCommands getInstance() {
    if (_instance == null)
      _instance = new GMCommands(); 
    return _instance;
  }
  
  private String complementClassName(String className) {
    if (className.contains("."))
      return className; 
    return "com.lineage.server.command.executor." + className;
  }
  
  private void executeDatabaseCommand(String cmd, String arg) {
    try {
      if (Config.ISUBUNTU && cmd.equalsIgnoreCase("sudo")) {
        _log.info("******Linux 系统命令执行**************************");
        ubuntuCommand(String.valueOf(String.valueOf(cmd)) + " " + arg);
        _log.info("******Linux 系统命令完成**************************");
        return;
      } 
      if (cmd.equalsIgnoreCase("c")) {
        _log.info("系统公告: " + arg);
        World.get().broadcastPacketToAll((ServerBasePacket)new S_HelpMessage(arg));
        RecordTable.get().recordeCmd("黑盒", cmd, arg, null);
        return;
      } 
      if (cmd.equalsIgnoreCase("debug")) {
        if (Config.DEBUG) {
          _log.info("终止除错模式!!");
          Config.DEBUG = false;
        } else {
          _log.info("启用除错模式!!");
          Config.DEBUG = true;
        } 
        return;
      } 
      L1Command command = CommandsTable.get().get(cmd.toLowerCase());
      if (command == null) {
        _log.error("指令异常: 没有这个命令(" + cmd.toLowerCase() + ")");
        return;
      } 
      if (!command.isSystem()) {
        _log.error("指令异常: 这个命令必须进入游戏才能执行(" + cmd.toLowerCase() + ")");
        return;
      } 
      Class<?> cls = Class.forName(complementClassName(command.getExecutorClassName()));
      L1CommandExecutor exe = (L1CommandExecutor)cls.getMethod("getInstance", new Class[0]).invoke(null, 
          new Object[0]);
      exe.execute(null, cmd.toLowerCase(), arg.toLowerCase());
      RecordTable.get().recordeCmd("黑盒", cmd, arg, null);
    } catch (Exception e) {
      _log.error("管理者指令异常!", e);
    } 
  }
  
  private void ubuntuCommand(String command) {
    try {
      Process process = Runtime.getRuntime().exec(command);
      BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
      String line = null;
      while ((line = input.readLine()) != null)
        _log.info("Linux 系统命令执行: " + line); 
    } catch (IOException e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
  
  public void handleCommands(String cmdLine) {
    String cmd;
    StringTokenizer token = new StringTokenizer(cmdLine);
    try {
      cmd = token.nextToken();
    } catch (Exception e) {
      _log.error("系统命令空白!");
      return;
    } 
    String param = "";
    while (token.hasMoreTokens())
      param = String.valueOf(param) + token.nextToken() + ' '; 
    param = param.trim();
    executeDatabaseCommand(cmd, param);
  }
  
  private boolean executeDatabaseCommand(L1PcInstance pc, String cmd, String arg) {
    try {
      L1Command command = CommandsTable.get().get(cmd.toLowerCase());
      if (command == null)
        return false; 
      if (pc.getAccessLevel() < command.getLevel() && !pc.hasSkillEffect(51239)) {
        pc.sendPackets((ServerBasePacket)new S_ServerMessage(74, "指令 " + cmd));
        return true;
      } 
      Class<?> cls = Class.forName(complementClassName(command.getExecutorClassName()));
      L1CommandExecutor exe = (L1CommandExecutor)cls.getMethod("getInstance", new Class[0]).invoke(null, 
          new Object[0]);
      exe.execute(pc, cmd.toLowerCase(), arg.toLowerCase());
      if (pc.getAccessLevel() > 0 && !pc.hasSkillEffect(51239))
        RecordTable.get().recordeCmd(pc.getName(), cmd, arg, pc.getIp()); 
      return true;
    } catch (Exception e) {
      _log.error("管理者指令异常!", e);
      return false;
    } 
  }
  
  public void handleCommands(L1PcInstance gm, String cmdLine) {
    String cmd;
    StringTokenizer token = new StringTokenizer(cmdLine);
    try {
      cmd = token.nextToken();
    } catch (Exception e) {
      _log.error("管理者指令空白!");
      return;
    } 
    String param = "";
    while (token.hasMoreTokens())
      param = String.valueOf(param) + token.nextToken() + ' '; 
    param = param.trim();
    if (executeDatabaseCommand(gm, cmd, param)) {
      if (!cmd.equalsIgnoreCase("r"))
        _lastCommands.put(Integer.valueOf(gm.getId()), cmdLine); 
      return;
    } 
    if (!cmd.equalsIgnoreCase("r")) {
      gm.sendPackets((ServerBasePacket)new S_ServerMessage(329, cmd));
      return;
    } 
    if (!_lastCommands.containsKey(Integer.valueOf(gm.getId()))) {
      gm.sendPackets((ServerBasePacket)new S_ServerMessage(261));
      return;
    } 
    redo(gm, param);
  }
  
  private void redo(L1PcInstance pc, String arg) {
    try {
      String lastCmd = _lastCommands.get(Integer.valueOf(pc.getId()));
      if (arg.isEmpty()) {
        pc.sendPackets((ServerBasePacket)new S_ServerMessage(166, "指令 " + lastCmd + " 重复执行"));
        handleCommands(pc, lastCmd);
      } else {
        StringTokenizer token = new StringTokenizer(lastCmd);
        String cmd = String.valueOf(String.valueOf(token.nextToken())) + " " + arg;
        pc.sendPackets((ServerBasePacket)new S_ServerMessage(166, "指令 " + lastCmd + " 纪录"));
        handleCommands(pc, cmd);
      } 
    } catch (Exception e) {
      pc.sendPackets((ServerBasePacket)new S_ServerMessage(261));
    } 
  }
}
